Skip to content

[Feat/#5] - 후기 작성 구현#12

Merged
goodispotato merged 13 commits intodevelopfrom
feature/create-review
Apr 18, 2026
Merged

[Feat/#5] - 후기 작성 구현#12
goodispotato merged 13 commits intodevelopfrom
feature/create-review

Conversation

@goodispotato
Copy link
Copy Markdown
Contributor

💻 관련 이슈

관련된 이슈 번호를 적어주세요.

✨ 작업 내용

이번 PR에서 작업한 내용을 간단하게 적어주세요.

  • 후기 작성 기능 구현

📄 상세 내용

작업의 상세 설명, 고려한 부분, 코드 구조 등에 대해 설명해 주세요.

  • 리뷰(줄글 후기들+태그), 스펙트럼(각 스펙트럼 및 값들) 값들을 한번에 저장 가능
  • 피그마 및 회의록 참고하여 태그와 스펙트럼 항목들 수정

📷 스크린샷

관련된 스크린샷이 있다면 첨부해 주세요.

✅ 체크리스트

PR을 보내기 전에 아래 항목들을 확인해 주세요.

  • 코드 컨벤션 준수
  • 빌드 성공
  • 로직 자체 테스트 완료
  • 불필요한 파일/코드 제거(개행 정리)
  • 이슈 번호 연결 확인
  • EOL(End Of Line) 확인

❕리뷰 요구 사항

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해 주세요.

  • 수정되면 좋을 것 같은 부분들 편하게 피드백 부탁드립니다!

@goodispotato goodispotato self-assigned this Apr 16, 2026
Copilot AI review requested due to automatic review settings April 16, 2026 11:22
@goodispotato goodispotato added the ✨feature 구현, 개선 사항 관련 부분 label Apr 16, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a review system, including the necessary entities, repositories, DTOs, and a service for creating reviews with associated tags and spectrum data. The review feedback highlights several critical performance and design improvements: addressing N+1 query issues in the service layer by batching database operations, improving encapsulation in DTOs, and adhering to RESTful standards and Java naming conventions. Additionally, suggestions were made to handle potential exceptions more robustly, avoid the use of @Setter in JPA entities, and ensure IDE-specific configuration files are excluded from the repository.

Comment thread SossBar/src/main/java/com/sossbar/review/service/ReviewService.java Outdated
Comment thread SossBar/src/main/java/com/sossbar/review/service/ReviewService.java Outdated
Comment thread .idea/.gitignore
Comment thread SossBar/src/main/java/com/sossbar/review/controller/ReviewController.java Outdated
Principal principal
) {
reviewService.createReview(principal, reviewCreateReqDto);
return ApiResTemplate.successWithNoContent(SuccessCode.SUCCESS);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

리소스 생성 요청에 대한 성공 응답으로는 200 OK보다 201 Created를 반환하는 것이 더 적절합니다.

Suggested change
return ApiResTemplate.successWithNoContent(SuccessCode.SUCCESS);
return ApiResTemplate.successWithNoContent(SuccessCode.CREATE_SUCCESS);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Valid 어노테이션 추가하고, 응답 형식을 nocontent가 아닌 ReviewResDto로 data에 값을 채워서 보내주어서 생성시에도 값을 바로 확인할 수 있게 하면 좋을 것 같아요 !!
+) 값 보내는 형식 예시 명세서에 추가해 놓으면 프론트분들 확인하시기 편할 듯 합니다 ..!!

Comment thread SossBar/src/main/java/com/sossbar/review/dto/request/ReviewCreateReqDto.java Outdated
Comment thread SossBar/src/main/java/com/sossbar/review/entity/Review.java Outdated
Comment thread SossBar/src/main/java/com/sossbar/review/repository/ReviewRepository.java Outdated
Comment thread SossBar/src/main/java/com/sossbar/review/service/ReviewService.java Outdated
Long reviewerIdentifier = Long.parseLong(principal.getName());

User reviewer = userRepository.findById(reviewerIdentifier)
.orElseThrow(() -> new RuntimeException("해당 유저는 존재하지 않습니다: " + reviewerIdentifier));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

RuntimeException과 같은 범용 예외보다는 구체적인 예외 상황을 설명할 수 있는 커스텀 예외를 정의하여 사용하는 것이 유지보수에 유리합니다.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the “후기 작성(Review Create)” feature by introducing review/tag/spectrum domain models and a write API, plus seed data for tags and spectrum axes.

Changes:

  • Add Review 작성 API (Controller/Service) 및 Review/ReviewTag/ReviewSpectrum JPA 모델/Repository/요청 DTO 구성
  • Tag, SpectrumAxis 기준정보(Entity/Repository/Response DTO) 추가 및 data.sql로 초기 데이터 시딩
  • application.yml에서 SQL init 동작 설정 추가

Reviewed changes

Copilot reviewed 20 out of 29 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
SossBar/src/main/resources/data.sql 태그/스펙트럼 축 초기 데이터 시딩 추가
SossBar/src/main/resources/application.yml SQL init 실행 설정 및 JPA 초기화 순서 설정 변경
SossBar/src/main/java/com/sossbar/tag/repository/TagRepository.java Tag 조회/저장용 JPA Repository 추가
SossBar/src/main/java/com/sossbar/tag/entity/Tag.java Tag 기준정보 엔티티 추가
SossBar/src/main/java/com/sossbar/tag/dto/response/TagResDto.java Tag 응답 DTO 추가
SossBar/src/main/java/com/sossbar/spectrumaxis/repository/SpectrumAxisRepository.java SpectrumAxis JPA Repository 추가
SossBar/src/main/java/com/sossbar/spectrumaxis/entity/SpectrumAxis.java SpectrumAxis 기준정보 엔티티 추가
SossBar/src/main/java/com/sossbar/spectrumaxis/dto/response/SpectrumAxisResDto.java SpectrumAxis 응답 DTO 추가
SossBar/src/main/java/com/sossbar/review/service/ReviewService.java 리뷰 생성 로직(태그/스펙트럼 동시 저장) 추가
SossBar/src/main/java/com/sossbar/review/repository/ReviewTagRepository.java ReviewTag Repository 추가
SossBar/src/main/java/com/sossbar/review/repository/ReviewSpectrumRepository.java ReviewSpectrum Repository 추가
SossBar/src/main/java/com/sossbar/review/repository/ReviewRepository.java Review Repository 및 중복검증 메서드 추가
SossBar/src/main/java/com/sossbar/review/entity/ReviewTag.java Review-Tag 조인 엔티티 추가
SossBar/src/main/java/com/sossbar/review/entity/ReviewSpectrum.java Review-Spectrum 조인 엔티티 추가
SossBar/src/main/java/com/sossbar/review/entity/Review.java Review 엔티티 추가
SossBar/src/main/java/com/sossbar/review/dto/response/ReviewResDto.java Review 응답 DTO 추가
SossBar/src/main/java/com/sossbar/review/dto/request/SpectrumReqDto.java 스펙트럼 요청 DTO 추가
SossBar/src/main/java/com/sossbar/review/dto/request/ReviewReqDto.java 리뷰(+태그) 요청 DTO 추가
SossBar/src/main/java/com/sossbar/review/dto/request/ReviewCreateReqDto.java 리뷰+스펙트럼 통합 요청 DTO 추가
SossBar/src/main/java/com/sossbar/review/controller/ReviewController.java 후기 작성 POST API 추가
.idea/vcs.xml IDE 설정 파일 추가(리포에 포함)
.idea/modules/sossbar.main.iml IDE 설정 파일 추가(리포에 포함)
.idea/modules.xml IDE 설정 파일 추가(리포에 포함)
.idea/misc.xml IDE 설정 파일 추가(리포에 포함)
.idea/gradle.xml IDE 설정 파일 추가(리포에 포함)
.idea/copilot.data.migration.ask2agent.xml IDE 설정 파일 추가(리포에 포함)
.idea/compiler.xml IDE 설정 파일 추가(리포에 포함)
.idea/JECT5-4th-Server.iml IDE 설정 파일 추가(리포에 포함)
.idea/.gitignore IDE 설정용 gitignore 파일 추가(리포에 포함)
Files not reviewed (9)
  • .idea/.gitignore: Language not supported
  • .idea/JECT5-4th-Server.iml: Language not supported
  • .idea/compiler.xml: Language not supported
  • .idea/copilot.data.migration.ask2agent.xml: Language not supported
  • .idea/gradle.xml: Language not supported
  • .idea/misc.xml: Language not supported
  • .idea/modules.xml: Language not supported
  • .idea/modules/sossbar.main.iml: Language not supported
  • .idea/vcs.xml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +44 to +55
User reviewer = userRepository.findById(reviewerIdentifier)
.orElseThrow(() -> new RuntimeException("해당 유저는 존재하지 않습니다: " + reviewerIdentifier));
User reviewee = userRepository.findById(reviewReqDto.getRevieweeId())
.orElseThrow(() -> new RuntimeException("해당 유저는 존재하지 않습니다: " + reviewReqDto.getRevieweeId()));

if (reviewRepository.existsByReviewerAndReviewee(reviewer, reviewee)) {
throw new IllegalStateException("이미 해당 유저에게 후기를 남긴 적이 있습니다.");
}

if (reviewer.getId().equals(reviewee.getId())) {
throw new IllegalStateException("자기 자신에게 후기를 남길 수 없습니다.");
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 RuntimeException/IllegalStateException을 던지고 있는데, CustomExceptionAdviceBusinessException만 별도 처리하고 그 외 예외는 500으로 내려보냅니다. 즉, "유저 없음", "중복 리뷰", "자기 자신 리뷰" 같은 검증/도메인 오류가 모두 500으로 응답될 수 있습니다. 기존 서비스들처럼 BusinessException + ErrorCode(필요 시 REVIEW 관련 ErrorCode 추가)로 변환해 4xx로 내려가도록 수정해 주세요.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +82
for (Long tagId : reviewReqDto.getTagIds()) {
reviewTagRepository.save(ReviewTag.builder()
.review(savedReview)
.tag(tagRepository.findById(tagId).orElseThrow(() -> new RuntimeException("해당 태그는 존재하지 않습니다: " + tagId)))
.build());
}

// 각 스펙트럼 축 당 저장하기
List<ReviewSpectrum> reviewSpectrums = reviewCreateReqDto.getSpectrumReqDtos().stream()
.map(spectrumReqDto -> {
SpectrumAxis spectrumAxis = spectrumAxisRepository.findById(spectrumReqDto.getSpectrumAxisId()).orElseThrow(() -> new RuntimeException("해당 스펙트럼은 존재하지 않습니다: " + spectrumReqDto.getSpectrumAxisId()));

return ReviewSpectrum.builder()
.review(savedReview)
.spectrumAxis(spectrumAxis)
.strength(spectrumReqDto.getSpectrumStrength())
.build();
})
.collect(Collectors.toList());

reviewSpectrumRepository.saveAll(reviewSpectrums);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

태그/스펙트럼 저장 시 ID마다 findById()를 호출해서 요청당 쿼리가 (태그 개수 + 스펙트럼 개수) 만큼 추가로 발생합니다. 태그/축 리스트가 커질 가능성이 있으면 findAllById()로 한 번에 조회해서 map으로 매핑하거나, 존재 검증을 포함한 배치 조회로 쿼리 수를 줄이는 방식이 더 효율적입니다.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +15
@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Review {
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review 엔티티에 Lombok @Setter가 전체 적용되어 있어 외부에서 리뷰의 작성자/대상자/프로젝트/피드백을 임의로 변경할 수 있습니다. 현재 코드베이스의 다른 엔티티들(User, Project)은 Getter 중심 + 명시적 update 메서드로 변경 지점을 제한하고 있으니, Review도 필요한 변경 메서드만 제공하고 @Setter는 제거(또는 접근 범위 제한)하는 편이 안정적입니다.

Copilot uses AI. Check for mistakes.

@Tag(name = "Review API", description = "후기 관련 API")
@RestController
@RequiredArgsConstructor
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 프로젝트의 다른 컨트롤러들은 공통 Swagger 응답 템플릿을 위해 클래스에 @SwaggerApiResTemplate를 붙이고 있습니다(예: UserController, ProjectController). ReviewController에도 동일한 템플릿을 적용하지 않으면 스웨거 응답 스펙이 컨트롤러별로 달라질 수 있으니, 필요하다면 클래스 레벨에 @SwaggerApiResTemplate를 추가해 일관성을 맞춰 주세요.

Suggested change
@RequiredArgsConstructor
@RequiredArgsConstructor
@com.sossbar.global.common.template.SwaggerApiResTemplate

Copilot uses AI. Check for mistakes.

public record SpectrumAxisResDto(
Long spectrumAxisId,
String spectrumAxisName,
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SpectrumAxisResDto에서 축 이름 필드가 spectrumAxisName으로 되어 있는데, 엔티티/DB 컬럼은 axisName(data.sql도 axis_name)으로 보입니다. DTO 필드명이 다르면 매핑 시 혼동/실수를 유발할 수 있으니, 실제 의미에 맞게 axisName 등으로 명확히 맞추는 것을 권장합니다.

Suggested change
String spectrumAxisName,
String axisName,

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +31
public ApiResTemplate createReview(
@RequestBody ReviewCreateReqDto reviewCreateReqDto,
Principal principal
) {
reviewService.createReview(principal, reviewCreateReqDto);
return ApiResTemplate.successWithNoContent(SuccessCode.SUCCESS);
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createReview의 반환 타입이 raw type인 ApiResTemplate로 선언되어 있습니다. 다른 컨트롤러들은 ApiResTemplate<Void>처럼 제네릭을 명시해서 타입 안정성을 유지하고 있으니, 여기에서도 ApiResTemplate<Void>(또는 no-content 전용 타입)로 맞춰 주세요.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to 21
sql:
init:
mode: always

jpa:
defer-datasource-initialization: true
hibernate:
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spring.profiles.activeprod로 고정된 상태에서 spring.sql.init.mode: always + data.sql을 추가하면, 프로덕션 기동 시마다 초기 데이터 INSERT가 반복 실행됩니다. 현재 tag_name에 유니크 제약이 없어 중복 데이터가 계속 쌓일 수 있으니, dev/profile에서만 실행하도록 분리(예: application-dev.yml에서만 always)하거나 mode를 embedded/never로 조정하고 초기 데이터는 마이그레이션(Flyway 등)로 관리하는 쪽이 안전합니다.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +28
@Operation(summary = "후기 작성", description = "사용자는 로그인 후 다른 사용자에 대한 후기를 남길 수 있습니다.")
@PostMapping("api/v1/reviews")
public ApiResTemplate createReview(
@RequestBody ReviewCreateReqDto reviewCreateReqDto,
Principal principal
) {
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요청 DTO에 validation 어노테이션이 선언되어 있는데(ReviewReqDto 등), 컨트롤러에서 @Valid가 빠져 있어 유효성 검사가 동작하지 않습니다. @Valid @RequestBody ReviewCreateReqDto로 검증을 활성화하고, 중첩 DTO까지 검증하려면 내부 필드에 @Valid를 추가해 주세요. (경로 문자열은 다른 컨트롤러들과 동일하게 leading /를 포함해 통일하는 것도 함께 고려해 주세요.)

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +25
INSERT INTO spectrum_axis(axis_name, left_label, right_label) VALUES ('1번 항목', '서포트형', '리드형');
INSERT INTO spectrum_axis(axis_name, left_label, right_label) VALUES ('2번 항목', '빠른 작업 속도 중시', '천천히 신중한 고민 중시');
INSERT INTO spectrum_axis(axis_name, left_label, right_label) VALUES ('3번 항목', '상황별 유연한 대처', '철저한 계획 기반 실행');
INSERT INTO spectrum_axis(axis_name, left_label, right_label) VALUES ('4번 항목', '냉철한 결과 지향', '따뜻한 관계 지향'); No newline at end of file
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이슈/PR 설명에는 후기 1개당 스펙트럼 항목 5개를 저장한다고 되어 있는데, 현재 seed 데이터(spectrum_axis)는 4개만 들어가 있고, createReview에서도 스펙트럼 리스트 길이/중복 축 여부를 검증하지 않습니다. 스펙트럼 축이 5개로 고정된 요구사항이라면 데이터/검증 로직을 5개 기준으로 맞추거나, 가변 개수로 설계할 거라면 PR 설명(또는 API 스펙)을 그에 맞게 업데이트해 주세요.

Copilot uses AI. Check for mistakes.
Comment thread .idea/vcs.xml
Comment on lines +1 to +6
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project> No newline at end of file
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IntelliJ .idea/ 설정 파일들이 PR에 포함되어 있습니다. 로컬 IDE 설정은 팀원/환경마다 달라 충돌을 유발하므로 보통 VCS에 커밋하지 않고 .gitignore(repo root)에 추가해 제외합니다. 이 PR에서는 .idea/** 파일들을 제거하고, 루트 .gitignore.idea/, *.iml 등을 추가하는 방식으로 정리해 주세요.

Suggested change
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@ttttkii913 ttttkii913 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생성 잘 되네요 !! 작업량 많았는데 고생 많으셨습니다 ..
코멘트 남겼으니 한 번 확인하시고 재희님 기존 방향이 맞을 수도 있으니 참고용으로 .. ! 확인해 주셔요 ~~

@@ -43,7 +48,6 @@ cloud:
secret-key: ${CLOUD_AWS_CREDENTIALS_SECRET_KEY}
s3:
bucket: ${CLOUD_AWS_S3_BUCKET}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 url 부분 다시 추가해서 올려주시면 좋을 것 같아요 !!
url: ${CLOUD_AWS_S3_URL}

Principal principal
) {
reviewService.createReview(principal, reviewCreateReqDto);
return ApiResTemplate.successWithNoContent(SuccessCode.SUCCESS);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Valid 어노테이션 추가하고, 응답 형식을 nocontent가 아닌 ReviewResDto로 data에 값을 채워서 보내주어서 생성시에도 값을 바로 확인할 수 있게 하면 좋을 것 같아요 !!
+) 값 보내는 형식 예시 명세서에 추가해 놓으면 프론트분들 확인하시기 편할 듯 합니다 ..!!

Copy link
Copy Markdown
Collaborator

@choeunbin03 choeunbin03 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 너무 고생 많으셨네요,,,,! 하영님이 말씀해주신 부분이랑 담에 혹시라도 예외 던질 때 커스텀 에러 사용해도 좋을 것 같아용 고생하셨습니다~!!👍👍

@goodispotato goodispotato merged commit 17baa66 into develop Apr 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨feature 구현, 개선 사항 관련 부분

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants